﻿#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//
//int main()
//{
//	struct S s = { "李四",23,88.5f };
//	//想把s中的数据存放在文件中
//	FILE* pf = fopen("test.txt", "w");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件 - 是以文本的形式写进去的
//	fprintf(pf, "%s %d %f", s.name, s.age, s.score);
//	
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//
//int main()
//{
//	struct S s = { 0};
//	//想从文件test.txt中把数据读取出来
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	fscanf(pf, "%s %d %f", &(s.name), &(s.age), &(s.score));
//
//	//打印在屏幕上
//	//printf("%s %d %f\n", s.name, s.age, s.score);
//	fprintf(stdout, "%s %d %f", s.name, s.age, s.score);
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//文件函数不仅可以输入到文件中，还可以输出到屏幕，stdout输出流，stdin输入流
//int main()
//{
//	fputc('a', stdout);//输出到屏幕
//	return 0;
//}

//对比一组函数
//scanf / fscanf / sscanf
//printf / fptintf / sprintf

//scanf - 从标准输入流上读取格式化的数据
//fscanf - 从指定的输入流上读取格式化的数据
//sscanf - 在字符串串中读取格式化的数据
//int sscanf(const char* s,const char* format,...);


//printf - 把数据以格式化的形式打印在标准输出流上
//fprintf - 把数据以格式化的形式打印在指定的输出流上
//sprintf - 把格式化的数据转化成字符串
//int sprintf(char* str,const char* format,…); 其实就是把格式化的数据转化成字符串了

//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//
//int main()
//{
//	char buf[200] = { 0 };
//	struct S s = { "张三",20,84.5f };
//	sprintf(buf, "%s %d %f", s.name, s.age, s.score);//把数据转化成字符串
//	
//	printf("%s\n", buf);//打印所有字符串
//	struct S t = { 0 };
//
//	return 0;
//}


//struct S
//{
//	char name[20];
//	int age;
//	float score;
//};
//
//int main()
//{
//	char buf[200] = { 0 };
//	struct S s = { "张三",20,84.5f };
//	sprintf(buf, "%s %d %f", s.name, s.age, s.score);//把数据转化成字符串
//
//	printf("1.以字符串的形式：%s\n", buf);//打印所有字符串
//
//	struct S t = { 0 };
//	sscanf(buf, "%s %d %f", t.name, &(t.age), &(t.score));
//	printf("2.按照格式形式  ：%s %d %f\n", t.name, t.age, t.score);
//
//	return 0;
//}


//fwrite
//size_T fwrite(const void* ptr,size_t size,size_t count,FILE* stream);

//fwrite函数的用法
//int main()
//{
//	int arr[] = { 1,2,3,4,5 };
//	FILE* pf = fopen("test.txt", "wb");//以二进制读写
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写数据
//	int sz = sizeof(arr) / sizeof(arr[0]);
//	fwrite(arr, sizeof(arr[0]), sz, pf);//以二进制的形式写进去
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//fread
//size_t fread(void* ptr,size_t size,size_count,FILE* stream);

//fread函数的用法
//以二进制的形式读取
//int main()
//{
//	int arr[5] = {0 };
//	FILE* pf = fopen("test.txt", "rb");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读数据
//	fread(arr, sizeof(arr[0]), 5, pf);
//	int i = 0;
//	for (i = 0; i < 5; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}

//上述代码另一种写法
//int main()
//{
//	int arr[5] = { 0 };
//	FILE* pf = fopen("test.txt", "rb");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读数据 - 以二进制的形式写进去的
//	int i = 0;
//	while (fread(&arr[i], sizeof(arr[0]), 1, pf))//当不知道文件中具体数据个数的时，用这种写法
//	{
//		printf("%d ", arr[i]);
//		i++;
//	}
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//文件的随机读写
//fseek
//							偏移量			起始位置
//int fseek(FILE* stream,long int offset,int origin):
//SEEK_SET  文件的起始位置
//SEEK_CUT  文件指针当前位置
//SEEK_END  文件末尾

//ftell
// 返回⽂件指针相对于起始位置的偏移量
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	char ch = fgetc(pf);
//	printf("%c\n", ch);//h
//
//	fseek(pf, 2, SEEK_SET);
//	ch = fgetc(pf);
//	printf("%c\n", ch);//l
//
//	//ftell用法
//	fseek(pf, -4, SEEK_END);
//	printf("%d\n", ftell(pf));//8
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//rewind
// 让⽂件指针的位置回到⽂件的起始位置
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	char ch = fgetc(pf);
//	printf("%c\n", ch);//a
//	fseek(pf, -4, SEEK_END);
//	ch = fgetc(pf);
//	printf("%c\n", ch);//f
//
//	rewind(pf);//让指针回到起始位置
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//#include <stdio.h>
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读文件
//	char ch = fgetc(pf);
//	printf("%c\n", ch);//h
//
//	fseek(pf, -4, SEEK_END);
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	//ftell用法
//	fseek(pf, -4, SEEK_END);
//	printf("%d\n", ftell(pf));//8
//	//关闭文件
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//返回起始位置
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//
//	//读文件
//	int ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	fseek(pf, -4, SEEK_END);
//
//	ch = fgetc(pf);
//	printf("%c\n", ch);
//
//	fclose(pf);
//	pf = NULL;
//
//	return 0;
//}


//文件读取结束的判定
//被错误使用的feof
//牢记：在文件读取过程中，不能使用feof函数的返回值直接来判断文件是否结束。
//feof的作用是：当文件读取结束的时候，判断是读取结束的原因是否是：遇到文件末尾结束/

//1.文本文件读取是否结束，判断返回值是否为EOF(fgetc)或者NULL（fgets）
//fgetc 判断是否为 EOF  -- 如果读取正常，返回的是读取到字符的ASCII码值
//						-- 如果读取的过程中遇到文件末尾，或者发生错误，就返回EOF
//fgets 判断返回值是否为 NULL -- 如果读取正常，返回的是存储读取到的字符串的字符数组的地址
//							  -- 如果读取的过程中遇到文件末尾，或者发生错误，返回NULL

//遇到文件末尾结束  feof
//读取的时候发生了错误  ferror

//打开的一个流的时候，这个流上有2个标记值：
//1.是否遇到文件末尾  2.是否发生错误

//2.二进制的读取结束判断，判断返回值是否小于实际要读的个数

//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//读取
//	int ch = 0;
//	while ((ch = fgetc(pf)) != EOF)
//	{
//		printf("%c\n", ch);
//	}
//	//判断是什么原因导致读取结束的
//	if (feof(pf))
//	{
//		printf("遇到文件末尾，读取正常结束\n");
//	}
//	else if (ferror(pf))
//	{
//		perror("fgetc");
//	}
//	fclose(pf);
//	pf = NULL;
//	return 0;
//}


//feof函数不是用来判断文件是否结束，而是文件的读取结束后，判断读取结束的原因是什么！！！
//测试文件发生错误
//int main()
//{
//	FILE* pf = fopen("test.txt", "r");
//	if (pf == NULL)
//	{
//		perror("fopen");
//		return 1;
//	}
//	//写文件
//	//发生错误
//	char ch = 0;
//	for (ch = 'a'; ch <= 'z'; ch++)
//	{
//		fputc(ch, pf);
//	}
//	//判断是什么原因导致读取结束的
//	if (feof(pf))
//	{
//		printf("遇到文件末尾，读取正常结束\n");
//	}
//	else if (ferror(pf))
//	{
//		perror("fgetc");
//	}
//	return 0;
//}


//拷贝文件 ：test1.txt -- >test2.txt
//int main()
//{
//	FILE* pfin = fopen("test.txt", "r");
//	if (pfin == NULL)
//	{
//		perror("fopen:test.txt");
//		return 1;
//	}
//
//	FILE* pfout = fopen("test2.txt", "w");
//	if (NULL == pfout)
//	{
//		fclose(pfin);//关闭test1.txt文件
//		perror("fopen:test2.txt");
//		return 1;
//	}
//
//	//边读边写文件
//	int ch = 0;
//	while((ch = fgetc(pfin)) != EOF)
//	{
//		fputc(ch, pfout);//写文件
//	}
//	fclose(pfin);
//	pfin = NULL;
//	fclose(pfout);
//	pfout = NULL;
//	return 0;
//}


//文件有缓冲区：
// 结论：因为有缓冲区的存在，C语言在操作文件的时候，
// 需要做刷新缓冲区或者在文件操作结束的时候关闭文件
#include <Windows.h>
//VS2022 WIN11环境测试
int main()
{
	FILE* pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先将代码放在输出缓冲区

	printf("睡眠10秒- 已经写数据了，打开test.txt文件，发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时，才将输出缓冲区的数据写到文件（磁盘）

	//注：fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时，再次打开test.txt文件，文件有内容了\n");
	//注：fclose在关闭文件的时候，也会刷新缓冲区
	pf = NULL;

	return 0;
}


//C语言代码 - 预处理 -- 编译 -- 汇编 -- 链接 -- 可执行程序
//《程序员的自我修养》

//extern int Add(int x, int y);
//int main()
//{
//	int a = 10;
//	int b = 30;
//	int ret = Add(a, b);
//	printf("ret = %d\n", ret);
//	return 0;
//}
